package org.leviatan.definator.gui.swingmodels;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;

import org.leviatan.definator.client.DefinatorServiceProxy;
import org.leviatan.definator.core.model.Field;
import org.leviatan.definator.core.model.Record;
import org.leviatan.definator.core.model.Table;
import org.leviatan.definator.gui.RuntimeContext;


public class DefinitionsTreeModel extends DefaultTreeModel {

	
	private static final long serialVersionUID = 1634821332872637990L;
	
	private DefaultMutableTreeNode theRoot;
	
	private HashMap<String, TableTreeNodeModel> tblNodeModels;
	private HashMap<String, RecordTreeNodeModel> recNodeModels;
	private HashMap<String, FieldTreeNodeModel> fldNodeModels;
	

	public DefinitionsTreeModel() {
		super(new DefaultMutableTreeNode("defs"));
		this.theRoot = (DefaultMutableTreeNode) this.getRoot();
		RuntimeContext.defTree = this;
		
		this.tblNodeModels = new HashMap<String, TableTreeNodeModel>();
		this.recNodeModels = new HashMap<String, RecordTreeNodeModel>();
		this.fldNodeModels = new HashMap<String, FieldTreeNodeModel>();
		
		this.buildTree();
		
		
	}
	
	public void buildTree() {
		
		Map tables = RuntimeContext.definatorService.getTableDefinitions();
		DefinatorServiceProxy proxy = RuntimeContext.definatorService;
		Collection records, fields;
		
		Record recModel;
		Field fldModel;
		TableTreeNodeModel tmpTblNode;
		RecordTreeNodeModel tmpRecNode;
		FieldTreeNodeModel tmpFldNode;
		
		// iterate tables
		for (Iterator i = tables.values().iterator(); i.hasNext(); ) {
			tmpTblNode = new TableTreeNodeModel((Table) i.next());
			this.theRoot.add(tmpTblNode);
			this.tblNodeModels.put(tmpTblNode.getId(), tmpTblNode);
			// get corr. rec ids
			records = proxy.getTablesRecordIds(tmpTblNode.getId());
			if (records == null) break;
			// and iterate those
			for(Iterator j = records.iterator(); j.hasNext(); ) {
				recModel = proxy.getRecordModel( (String) j.next() );
				tmpRecNode = new RecordTreeNodeModel(recModel);
				tmpTblNode.add(tmpRecNode);
				this.recNodeModels.put(tmpRecNode.getId(), tmpRecNode);
				// get corr. fld ids
				fields = proxy.getRecordsFieldIds(tmpRecNode.getId());
				if (fields == null ) break;
				// and iterate those
				for (Iterator k = fields.iterator(); k.hasNext(); ) {
					fldModel = proxy.getFieldModel((String) k.next());
					tmpFldNode = new FieldTreeNodeModel(fldModel);
					tmpRecNode.add(tmpFldNode);
					this.fldNodeModels.put(tmpFldNode.getId(), tmpFldNode);
				}
			}
			
			
		}
		
	}
	
	public void reload() {
		this.theRoot.removeAllChildren();
		this.buildTree();
		super.reload();
	}
	
	public void updateTableNode(String aId) {
		TableTreeNodeModel nodeObj = this.tblNodeModels.get(aId);
		Table tbl = RuntimeContext.definatorService.getTableModel(aId);
		
		nodeObj.setName(tbl.getName());
		
		this.nodeChanged(nodeObj);

	}
	
	public void updateRecordNode(String aId) {
		
		RecordTreeNodeModel nodeObj = this.recNodeModels.get(aId);
		Record rec = RuntimeContext.definatorService.getRecordModel(aId);
		
		nodeObj.setName(rec.getName());
		
		this.nodeChanged(nodeObj);
	}
	
	public void updateFieldNode(String aId) {
		
		FieldTreeNodeModel node = this.fldNodeModels.get(aId);
		Field fld = RuntimeContext.definatorService.getFieldModel(aId);
		
		node.setLength(fld.getLength());
		node.setName(fld.getName());
		node.setType(fld.getType());
		
		this.nodeChanged(node);
		
	}
	
	public void tableModelAdded(String id) {
		Table tbl = RuntimeContext.definatorService.getTableModel(id);
		TableTreeNodeModel tblNode = new TableTreeNodeModel(tbl);
		this.tblNodeModels.put(id, tblNode);
		this.theRoot.add(tblNode);
		
		int index = this.theRoot.getIndex(tblNode);
		this.nodesWereInserted(this.theRoot, new int[] {index} );
		
	}
	
	public void recordModelAdded(String id, String tblId) {
		Record rec = RuntimeContext.definatorService.getRecordModel(id);
		RecordTreeNodeModel recNode = new RecordTreeNodeModel(rec);
		DefaultMutableTreeNode superNode = null;
		int index;
		if (tblId != null && !tblId.equals("")) {
			superNode = this.tblNodeModels.get(tblId);
		}
		else {
			superNode = this.theRoot;
		}
		superNode.add(recNode);
		
		index = superNode.getIndex(recNode);
		this.nodesWereInserted(superNode, new int[] {index} );
		
		this.recNodeModels.put(id, recNode);
		
	}
	
	public void fieldModelAdded(String id, String recId) {
		Field fld = RuntimeContext.definatorService.getFieldModel(id);
		FieldTreeNodeModel fldNode= new FieldTreeNodeModel(fld);
		DefaultMutableTreeNode superNode = null;
		int index;
		
		if (recId != null && !recId.equals("")) superNode = this.recNodeModels.get(recId);
		else superNode = this.theRoot;
		
		this.fldNodeModels.put(id, fldNode);
		superNode.add(fldNode);
		
		index = superNode.getIndex(fldNode);
		this.nodesWereInserted(superNode, new int[] {index} );
		
	}
	
	public void fieldNodeDeleted(String id) {
		FieldTreeNodeModel fld = this.fldNodeModels.get(id);
		DefaultMutableTreeNode superNode = (DefaultMutableTreeNode) fld.getParent();
		int index = superNode.getIndex(fld);
		FieldTreeNodeModel[] objA = {fld};
		this.nodesWereRemoved(superNode, new int[]{index}, objA);
		
		// last thing
		this.fldNodeModels.remove(id);
	}
	
	public void recordNodeDeleted(String id) {
		RecordTreeNodeModel rec = this.recNodeModels.get(id);
		DefaultMutableTreeNode superNode = (DefaultMutableTreeNode) rec.getParent();
		int index = superNode.getIndex(rec);
		RecordTreeNodeModel[] objA = {rec};
		this.nodesWereRemoved(superNode, new int[]{index}, objA);
		
		// last thing
		this.recNodeModels.remove(id);	
	}
	
	public void tableNodeDeleted(String id) {
		TableTreeNodeModel tbl = this.tblNodeModels.get(id);
		DefaultMutableTreeNode superNode = (DefaultMutableTreeNode) tbl.getParent();
		int index = superNode.getIndex(tbl);
		TableTreeNodeModel[] objA = {tbl};
		this.nodesWereRemoved(superNode, new int[]{index}, objA);
		
		// last thing
		this.tblNodeModels.remove(id);
	}
	
	public void nodeDeleted(DefaultMutableTreeNode selectedNode) {
		Object nodeModel = selectedNode.getUserObject();
		if (nodeModel instanceof FieldTreeNodeModel) {
			
		}
		else if (nodeModel instanceof TableTreeNodeModel) {
			
		}
		else if (nodeModel instanceof RecordTreeNodeModel) {
			
		}
		
		int index = selectedNode.getParent().getIndex(selectedNode);
		Object[] objA = {selectedNode};
		this.nodesWereRemoved(selectedNode.getParent(), new int[] {index}, objA);
	}

	public HashMap<String, FieldTreeNodeModel> getFldNodeModels() {
		return this.fldNodeModels;
	}

	public HashMap<String, RecordTreeNodeModel> getRecNodeModels() {
		return this.recNodeModels;
	}

	public HashMap<String, TableTreeNodeModel> getTblNodeModels() {
		return this.tblNodeModels;
	}
	
	


	


	

}
